package br.com.hs.nfe.common.util;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;

/**
 *
 * @author ranlive
 */
public class StringHelper {

    private static final int TAMANHO_CNPJ = 14;
    private static final int TAMANHO_CNPJ_BASE_FORMAT = 8;
    private static final int TAMANHO_CPF = 11;
    private static final int POSICAO_DIGITO_CPF = 12;
    private static final int TAMANHO_NUMERO_NOTA = 9;
    private static final int TAMANHO_CODIGO_NUMERICO = 9;

    /**
     * Verifica se um objeto é nulo ou vazio.
     * @param value Objeto.
     * @return true se nulo ou false se não.
     */
    public static boolean isBlankOrNull(Object value) {
        return (value == null) || (value.toString().trim().isEmpty());
    }

    /**
     * Retorna nulo se for vazio;
     * @param s Texto.
     * @return null ou texto;
     */
    public static String getNullIfEmpty(String s) {
        if (isBlankOrNull(s)) {
            return null;
        }
        return s.trim();
    }

    /**
     * Converte uma string em integer.
     * @param strInt String.
     * @return null ou integer.
     */
    public static Integer getInteger(String strInt) {
        try {
            strInt = strInt.trim();
            return new Integer(strInt);
        } catch (Exception ex) {
        }
        return null;
    }

    /**
     * Retira pontuação do número do documento.
     * @param nrDocumento Número do documento.
     * @return Documento sem pontuação.
     */
    public static String unformatDocument(String nrDocumento) {
        StringBuilder retorno = new StringBuilder(nrDocumento);
        if (!isBlankOrNull(nrDocumento)) {
            for (int ci = 0; ci < retorno.length(); ci++) {
                char carac = retorno.charAt(ci);
                if ((carac == '.') || (carac == '-') || (carac == '/')) {
                    retorno.deleteCharAt(ci);
                }
            }
        }
        return retorno.toString();
    }

    /**
     * Completa uma String com zeros a esquerda.
     * @param str String.
     * @param finalLength Tamanho final.
     * @return String formatada.
     */
    public static String completarComZerosAEsquerda(String str, int finalLength) {
        StringBuilder sb = new StringBuilder();
        if (!isBlankOrNull(str)) {
            for (int ci = 0; ci < finalLength - str.length(); ci++) {
                sb.append("0");
            }
            sb.append(str);
        } else {
            for (int ci = 0; ci < finalLength; ci++) {
                sb.append("0");
            }
        }
        return sb.toString();
    }

    /**
     * Formata um CEP.
     * @param cep
     * @return
     */
    public static String formatarCEP(String cep) {
        String retorno = "";
        if (cep != null) {
            int len = cep.length();
            retorno = "";
            if (len >= 5) {
                retorno = retorno + cep.substring(0, 5) + "-";
                if (len > 5) {
                    retorno += cep.substring(5);
                } else {
                    retorno += "000";
                }
            } else {
                retorno = cep;
            }
        }
        return retorno;
    }

    /**
     * Formata um NCM.
     * @param ncm
     * @return
     */
    public static String formatarNCM(String ncm) {
        String retorno = "";
        if (!isBlankOrNull(ncm)) {
            ncm = unformatDocument(ncm);
            if (ncm.length() == 8) {
                retorno = ncm.substring(0, 4) + "." + ncm.substring(4, 6) + "." + ncm.substring(6, 8);
            } else {
                retorno = ncm;
            }
        }
        return retorno;
    }

    /**
     * Remove a formatação do NCM.
     * @param ncm
     * @return
     */
    public static String unformatNCM(String ncm) {
        StringBuilder sb = new StringBuilder();
        sb.append(completarComZerosAEsquerda(removeChar(ncm, '.'), 8));
        return sb.toString();
    }

    /**
     * Remove o caracter especificado de toda a String.
     * @param s
     * @param c
     * @return
     */
    public static String removeChar(String s, char c) {
        String r = "";
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == c) {
                continue;
            }
            r += s.charAt(i);
        }
        return r;
    }

    /**
     * Formata um CNPJ
     * @param cnpj
     * @return
     */
    public static String cnpjFormat(String cnpj) {
        StringBuilder cnpjFormatado = new StringBuilder();
        if (!isBlankOrNull(cnpj)) {
            String cnpjCompleto = completarComZerosAEsquerda(cnpj, TAMANHO_CNPJ);
            cnpjFormatado.append(cnpjCompleto.substring(0, 2));
            cnpjFormatado.append(".");
            cnpjFormatado.append(cnpjCompleto.substring(2, 5));
            cnpjFormatado.append(".");
            cnpjFormatado.append(cnpjCompleto.substring(5, 8));
            cnpjFormatado.append("/");
            cnpjFormatado.append(cnpjCompleto.substring(8, POSICAO_DIGITO_CPF));
            cnpjFormatado.append("-");
            cnpjFormatado.append(cnpjCompleto.substring(POSICAO_DIGITO_CPF, 14));
        }

        return cnpjFormatado.toString();
    }

    /**
     * Formata um CPF.
     * @param cpf
     * @return
     */
    public static String cpfFormat(String cpf) {
        StringBuilder cpfFormatado = new StringBuilder();
        if (!isBlankOrNull(cpf)) {
            String cpfCompleto = completarComZerosAEsquerda(cpf, TAMANHO_CPF);
            cpfFormatado.append(cpfCompleto.substring(0, 3));
            cpfFormatado.append(".");
            cpfFormatado.append(cpfCompleto.substring(3, 6));
            cpfFormatado.append(".");
            cpfFormatado.append(cpfCompleto.substring(6, 9));
            cpfFormatado.append("-");
            cpfFormatado.append(cpfCompleto.substring(9, 11));
        }
        return cpfFormatado.toString();
    }

    /**
     * Formata um CNPJ ou CPF baseando-se no tamanho da String.
     * @param nrDocumento
     * @return
     */
    public static String documentoFormat(String nrDocumento) {
        String retorno = nrDocumento;
        if (!isBlankOrNull(nrDocumento)) {
            if (nrDocumento.length() == TAMANHO_CPF) {
                retorno = cpfFormat(nrDocumento);
            } else if (nrDocumento.length() == TAMANHO_CNPJ) {
                retorno = cnpjFormat(nrDocumento);
            }
        }

        return retorno;
    }

    /**
     * Formata CNPJ sem barras ou traços.
     * @param cnpjBase
     * @return
     */
    public static String cnpjBaseFormat(String cnpjBase) {
        StringBuilder retorno = new StringBuilder();
        if (!isBlankOrNull(cnpjBase)) {
            String cnpjCompleto = completarComZerosAEsquerda(cnpjBase, TAMANHO_CNPJ_BASE_FORMAT);
            retorno.append(cnpjCompleto.substring(0, 2));
            retorno.append(".");
            retorno.append(cnpjCompleto.substring(2, 5));
            retorno.append(".");
            retorno.append(cnpjCompleto.substring(5, 8));
        }

        return retorno.toString();
    }

    /**
     * Remove espaços.
     * @param value
     * @return
     */
    public static String trim(String value) {
        String retorno = null;
        if (value != null) {
            retorno = value.trim();
        }
        return retorno;
    }

    /**
     * Redimetniona String removendo excesso ou aciononando espaços se necessário.
     * @param str
     * @param length
     * @return
     */
    public static String redimensionaString(String str, int length) {
        String retorno = null;
        if (str != null) {
            String strTrim = str.trim();
            retorno = strTrim.concat(stringVazia(length - strTrim.length()));
        } else {
            retorno = stringVazia(length);
        }
        return retorno;
    }

    /**
     * Retorna uma String com a quantidade de espaços especificados.
     * @param length
     * @return
     */
    public static String stringVazia(int length) {
        if (length <= 0) {
            return "";
        }
        StringBuilder sb = new StringBuilder(length);
        for (int ci = 0; ci < length; ci++) {
            sb.append(" ");
        }
        return sb.toString();
    }

    /**
     * Retira pontos, e converte vírgulas para pontos.
     * @param valor
     * @return
     */
    public static String formatarValorXML(String valor) {
        return valor.replace(".", "").replace(",", ".");
    }

    /**
     * Formata um valor numerico e retorna uma String.
     */
    public static String formatarValor(double d, int maximumIntegerDigits, int maximumFractionDigits) {
        DecimalFormat df = new DecimalFormat();

        df.setDecimalFormatSymbols(new DecimalFormatSymbols(new Locale("pt", "BR")));
        df.setMaximumIntegerDigits(maximumIntegerDigits);
        df.setMaximumFractionDigits(maximumFractionDigits);

        return df.format(d);
    }

    /**
     * Formata uma String como numerico.
     */
    public static String formatarValor(String s, int maximumIntegerDigits, int maximumFractionDigits) {
        if (!StringHelper.isBlankOrNull(s)) {
            return formatarValor(new BigDecimal(s), maximumIntegerDigits, maximumFractionDigits).toString();
        }
        return null;
    }

    /**
     * Formata um BigDecimal e retorna uma String.
     */
    public static String formatarValor(BigDecimal b, int maximumIntegerDigits, int maximumFractionDigits) {
        if (b == null) {
            return "";
        }

        DecimalFormat df = new DecimalFormat();
        df.setDecimalFormatSymbols(new DecimalFormatSymbols(new Locale("pt", "BR")));
        df.setMaximumIntegerDigits(maximumIntegerDigits);
        df.setMaximumFractionDigits(maximumFractionDigits);

        return df.format(b);
    }

    /**
     * Formata númeracao da Nota Fiscal.
     * @param nota
     * @return
     */
    public static String formatarNotaFiscal(String nota) {
        StringBuilder sb = new StringBuilder();
        if (!isBlankOrNull(nota)) {
            String notaCompleto = completarComZerosAEsquerda(nota, TAMANHO_NUMERO_NOTA);
            sb.append(notaCompleto.substring(0, 3)).append(".");
            sb.append(notaCompleto.substring(3, 6)).append(".");
            sb.append(notaCompleto.substring(6, 9));
        }
        return sb.toString();
    }

    /**
     * Formata Código Numérico da Nota Fiscal.
     * @param codNum
     * @return
     */
    public static String formatarCodigoNumerico(String codNum) {
        StringBuilder sb = new StringBuilder();
        if (!isBlankOrNull(codNum)) {
            String notaCompleto = completarComZerosAEsquerda(codNum, TAMANHO_CODIGO_NUMERICO);
            sb.append(notaCompleto.substring(0, 3)).append(".");
            sb.append(notaCompleto.substring(3, 6)).append(".");
            sb.append(notaCompleto.substring(6, 9));
        }
        return sb.toString();
    }

    /**
     * Formara Nota Fiscal Referenciada
     * @param nota
     * @return
     */
    public static String formatarNotaFiscalRef(String nota) {
        StringBuilder sb = new StringBuilder(nota);
        if (sb.length() == 44) {
            sb.insert(2, "-").insert(5, "/").insert(8, "-").insert(11, ".").insert(15, ".");
            sb.insert(19, "/").insert(24, "-").insert(27, "-").insert(30, "-").insert(34, "-");
            sb.insert(38, ".").insert(42, ".").insert(46, "-").insert(50, ".").insert(54, ".").insert(58, "-");
        } else {
            return null;
        }
        return sb.toString();
    }

    /**
     * Substitui valores.
     * @param find Valor a procurar.
     * @param replace Novo valor.
     * @param source Texto em que será feita a procura.
     * @return
     */
    public static String replace(String find, String replace, String source) {
        String result = "";
        for (; source.indexOf(find) >= 0; source = source.substring(source.indexOf(find) + find.length())) {
            result = result + source.substring(0, source.indexOf(find)) + replace;
        }
        result += source;
        return result;
    }

    /**
     * Retorna true se for um númerico.
     * @param str
     * @return
     */
    public static boolean isNumeric(String str) {
        if (isBlankOrNull(str)) {
            return false;
        }
        try {
            Double.parseDouble(str);
            return true;
        } catch (NumberFormatException ex) {
        }
        return false;
    }

    /**
     * Retorna true se for um inteiro.
     * @param str
     * @return
     */
    public static boolean isInteger(String str) {
        if (isBlankOrNull(str)) {
            return false;
        }
        try {
            Integer.parseInt(str);
            return true;
        } catch (NumberFormatException ex) {
        }
        return false;
    }

    /**
     * Obtém os digitos de uma String.
     * @param string
     * @return
     */
    public static String getDigits(String string) {
        return string.replaceAll("\\D", "");
    }

    /**
     * Retira pontuação de String monetária.
     * @param string
     * @return
     */
    public static String getMoney(String string) {
        return string.replaceAll("[.]", "");
    }

    /**
     * Completa a esquerda com o valor especificado.
     * @param string
     * @param pad
     * @param tamanhoFinal
     * @return
     */
    public static String leftPad(Object string, String pad, int tamanhoFinal) {
        String resultado = string.toString();
        while (resultado.length() < tamanhoFinal) {
            resultado = pad + resultado;
        }
        return resultado;
    }

    /**
     * Retorna true se for um valor repetido.
     * @param value
     * @return
     */
    public static boolean isRepeated(String value) {
        boolean isRepeated = true;

        String character = value.substring(0, 1);

        for (int i = 1; i < value.length(); i++) {
            String nextChar = value.substring(i, i + 1);

            if (!nextChar.equals(character)) {
                isRepeated = false;
                break;
            }
        }

        return isRepeated;
    }

    /**
     * Substitui caracters do XML retirando pontuação.
     * @param str
     * @return
     */
    public static String encodeSpecialXMLChars(String str) {
        if (str == null) {
            return null;
        }
        return str.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&#39;");
    }

    /**
     * Substitui caracters do XML recolocando pontuação.
     * @param str
     * @return
     */
    public static String decodeSpecialXMLChars(String str) {
        if (str == null) {
            return null;
        }
        return str.replaceAll("&amp;", "&").replaceAll("&lt;", "<").replaceAll("&gt;", ">").replaceAll("&quot;", "\"").replaceAll("&#39;", "'");
    }
}
